import { AsyncData, useFetch, UseFetchOptions, useNuxtApp } from "#app";
import { computed, useGlobalCookie } from "#imports";

const HeaderFilter: string[] = import.meta.env.VITE_SSR_HEADER_FILTER?.split(
  ","
).map(v => v.toLowerCase()) || ["connection", "accept-encoding", "host"];

export interface DiscuzAPIResponse<T> {
  Code: number;
  Message: string;
  Data: T;
  RequestId: string;
  RequestTime: string;
}

const makeRequest = <T>(
  url: string,
  key: string,
  fetchOption?: UseFetchOptions<DiscuzAPIResponse<T | null>>
) => {
  const AccessToken = useGlobalCookie("access_token");
  const opt: UseFetchOptions<DiscuzAPIResponse<T | null>> = {
    key: key,
    ...fetchOption,
    onRequest(ctx) {
      fetchOption?.onRequest?.(ctx);
      if (AccessToken.value) {
        headers["Authorization"] = `Bearer ${AccessToken.value}`;
      } else {
        delete headers["Authorization"];
      }
    }
  };
  if (!opt.headers) opt.headers = {};
  const headers = opt.headers as Record<string, string>;
  if (import.meta.env.SSR) {
    const ReqHeaders = useNuxtApp().ssrContext?.event.req?.headers;
    if (ReqHeaders) {
      Object.keys(ReqHeaders)
        .filter(key => !HeaderFilter.includes(key.toLowerCase()))
        .map(key => (headers[key] = <string>ReqHeaders[key]));
    }
    headers["x-render-context"] = "SSR";
  } else {
    headers["x-render-context"] = "CSR";
  }
  const inst = useFetch<DiscuzAPIResponse<T | null>>("/api/v3" + url, opt);
  const { data } = inst;
  inst.data = computed(() => data.value?.Data ?? null) as never;
  inst.error = computed(() => {
    if (import.meta.env.SSR && fetchOption?.server === false) {
      return false;
    }
    if (data.value) {
      if (data.value.Code === 0) return false;
      return { Code: data.value.Code, Message: data.value.Message };
    } else if (fetchOption?.immediate === false) {
      return false;
    } else {
      return { Code: -1, Message: "Unknown Error" };
    }
  }) as never;
  return inst as unknown as AsyncData<
    T | null,
    { Code: number; Message: string }
  >;
};
const useAsyncGet = <T>(
  url: string,
  key: string,
  params?: Record<string, unknown>,
  fetchOption?: UseFetchOptions<DiscuzAPIResponse<T | null>>
) => {
  return makeRequest<T>(url, key, {
    params,
    ...fetchOption
  });
};
const useAsyncPost = <T>(
  url: string,
  key: string,
  data: unknown,
  fetchOption?: UseFetchOptions<DiscuzAPIResponse<T | null>>
) => {
  return makeRequest<T>(url, key, {
    body: data as never,
    method: "POST",
    ...fetchOption
  });
};
const useAsyncPut = <T>(
  url: string,
  key: string,
  data: unknown,
  fetchOption?: UseFetchOptions<DiscuzAPIResponse<T | null>>
) => {
  return makeRequest<T>(url, key, {
    body: data as never,
    method: "PUT",
    ...fetchOption
  });
};
const useAsyncDelete = <T>(
  url: string,
  key: string,
  data: unknown,
  fetchOption?: UseFetchOptions<DiscuzAPIResponse<T | null>>
) => {
  return makeRequest<T>(url, key, {
    body: data as never,
    method: "DELETE",
    ...fetchOption
  });
};
export { useAsyncGet, useAsyncPost, useAsyncPut, useAsyncDelete };
